function glm = importrfxglmfromspms(spms, opts)
% importrfxglmfromspms  - import beta maps from SPM into a BVQX GLM file
%
% FORMAT:       glm = importrfxglmfromspms(spms, opts)
%
% Input fields:
%
%       spms        list of SPM.mat filenames to use for import
%       opts        options for the import
%        .bbox      MNI/TAL bounding box to use
%        .cond      1xC structure with fields (default: auto detect)
%         .bvname   condition name for the BV file
%         .spmname  SPM based name (or pattern)
%        .filename  output GLM filename (otherwise unsaved)
%        .imeth     interpolation method: 'cubic', {'linear'}, 'nearest'
%        .mmaskfac  mean-masking factor, default 0.5
%                   results in masking out voxels where constant < 0.5
%                   of its mean overall value (per subject)
%        .pbar      either BVQXprogress or BVQXfigure:XProgress object
%        .res       resolution (default: floor of SPM resolution)
%        .subjids   subject identifiers (default: auto detect)
%        .trans     either {'none'}, 'psc'
%                   PSC-transform uses estimated mean (constant) as 100!
%
% Output fields:
%
%       glm         GLM object (saved if .filename is given)

% Version:  v0.8a
% Build:    9102720
% Date:     Oct-27 2009, 8:47 PM CET
% Author:   Jochen Weber, SCAN Unit, Columbia University, NYC, NY, USA
% URL/Info: http://wiki.brainvoyager.com/BVQXtools

% variable for UI stuff
global BVQXui;

% allow UI call
if nargin > 0 && ...
    ischar(spms) && ...
    strcmpi(spms(:)', 'ui')

    % open figure
    try
        hFig = BVQXfigure([bvqxtools_path('tfg') '/importrfxglmfromspms.tfg']);
    catch
        error( ...
            'BVQXtools:BVQXfigureError', ...
            'Error creating UI for GLM import: %s.', ...
            lasterr ...
        );
    end
    
    % initialize global variable
    hTag = hFig.TagStruct;
    BVQXui.importrfxglmfromspms = struct( ...
        'glm',  [], ...
        'hFig', hFig, ...
        'hTag', hTag);
    
    % prepare listboxes
    hTag.LB_importrfxglm_files.Value = [];
    hTag.LB_importrfxglm_files.String = {};
    hTag.LB_importrfxglm_spmcond.Value = [];
    hTag.LB_importrfxglm_spmcond.String = {};
    hTag.LB_importrfxglm_glmcond.Value = [];
    hTag.LB_importrfxglm_glmcond.String = {};
    
    % set callbacks
    hTag.BT_importrfxglm_folder.Callback = @ig_btbrowse;
    hTag.BT_importrfxglm_search.Callback = @ig_btsearch;
    hTag.BT_importrfxglm_fdown.Callback = @ig_btfiledown;
    hTag.BT_importrfxglm_fup.Callback = @ig_btfileup;
    hTag.BT_importrfxglm_fplus.Callback = @ig_btfileadd;
    hTag.BT_importrfxglm_fminus.Callback = @ig_btfileremove;
    hTag.LB_importrfxglm_spmcond.Callback = @ig_lbspmcselect;
    hTag.LB_importrfxglm_glmcond.Callback = @ig_lbglmcselect;
    hTag.BT_importrfxglm_cdown.Callback = @ig_btconddown;
    hTag.BT_importrfxglm_cup.Callback = @ig_btcondup;
    hTag.BT_importrfxglm_cplus.Callback = @ig_btcondadd;
    hTag.BT_importrfxglm_cminus.Callback = @ig_btcondremove;
    hTag.CB_importrfxglm_autcond.Callback = @ig_toggleautocond;
    hTag.CB_importrfxglm_autores.Callback = @ig_toggleautores;
    hTag.BT_importrfxglm_cancel.Callback = @ig_closeui;
    hTag.BT_importrfxglm_import.Callback = @ig_btimport;
    
    % options given?
    pbar = [];
    if nargin > 1 && ...
        isstruct(opts) && ...
        numel(opts) == 1
        if isfield(opts, 'pbar')
            pbar = opts.pbar;
        end
    end
    BVQXui.importrfxglmfromspms.pbar = pbar;
    
    % make figure modal
    hFig.Visible = 'on';
    hFig.WindowStyle = 'modal';
    
    % wait for figure to close
    uiwait(hFig.mlhandle);
    
    % assign GLM output
    glm = BVQXui.importrfxglmfromspms.glm;
    BVQXui.importrfxglmfromspms = [];
    if ~isempty(glm)
        glm = bless(glm);
    end
    
    % return
    return;
end

% argument check
if nargin < 1 || ...
   ~iscell(spms) || ...
    isempty(spms)
    error( ...
        'BVQXtools:BadArgument', ...
        'At least three subjects needed for RFX GLM.' ...
    );
end
if nargin < 2 || ...
   ~isstruct(opts) || ...
    numel(opts) ~= 1
    opts = struct;
end
if ~isfield(opts, 'bbox') || ...
   ~isa(opts.bbox, 'double') || ...
   ~isequal(size(opts.bbox), [2, 3]) || ...
    any(isnan(opts.bbox(:)) | opts.bbox(:) < 0 | opts.bbox(:) > 255)
    opts.bbox = [];
else
    opts.bbox = round(opts.bbox);
end
if ~isfield(opts, 'cond') || ...
   ~isstruct(opts.cond) || ...
   ~isfield(opts.cond, 'bvname') || ...
   ~isfield(opts.cond, 'color') || ...
   ~isfield(opts.cond, 'spmname')
    opts.cond = cell2struct(cell(0, 0, 3), {'bvname', 'color', 'spmname'}, 3);
end
if ~isfield(opts, 'filename') || ...
   ~ischar(opts.filename) || ...
    isempty(opts.filename) || ...
    numel(opts.filename) > 255
    opts.filename = '';
else
    opts.filename = opts.filename(:)';
end
if ~isfield(opts, 'imeth') || ...
   ~ischar(opts.imeth) || ...
   ~any(strcmpi(opts.imeth(:)', {'cubic', 'linear', 'nearest'}))
    opts.imeth = 'linear';
else
    opts.imeth = lower(opts.imeth(:)');
end
if ~isfield(opts, 'mmaskfac') || ...
   ~isa(opts.mmaskfac, 'double') || ...
    numel(opts.mmaskfac) ~= 1 || ...
    isinf(opts.mmaskfac) || ...
    isnan(opts.mmaskfac) || ...
    opts.mmaskfac < 0 || ...
    opts.mmaskfac > 2
    opts.mmaskfac = 0.5;
end
if ~isfield(opts, 'pbar') || ...
    numel(opts.pbar) ~= 1 || ...
   ~any(strcmpi(class(opts.pbar), {'bvqxfigure', 'bvqxprogress'}))
    opts.pbar = [];
end
if ~isfield(opts, 'res') || ...
   ~isa(opts.res, 'double') || ...
    numel(opts.res) ~= 1 || ...
   ~any((1:4) == opts.res)
    opts.res = [];
end
if ~isfield(opts, 'subjids') || ...
   ~iscell(opts.subjids) || ...
    numel(opts.subjids) ~= numel(spms)
    opts.subjids = {};
end
if numel(spms) == 1 && ...
    isempty(opts.subjids)
    error( ...
        'BVQXtools:BadArgument', ...
        'For single subject, a subject ID must be given.' ...
    );
end
for sc = 1:numel(opts.subjids)
    if ~ischar(opts.subjids{sc}) || ...
        isempty(opts.subjids{sc}) || ...
        numel(opts.subjids{sc}) > 63
        opts.subjids = {};
        break;
    else
        opts.subjids{sc} = opts.subjids{sc}(:)';
    end
end
if ~isempty(opts.subjids)
    if numel(opts.subjids) ~= numel(spms) || ...
        numel(unique(lower(opts.subjids))) ~= numel(spms)
        opts.subjids = {};
    end
end
if ~isfield(opts, 'trans') || ...
   ~ischar(opts.trans) || ...
   ~any(strcmpi(opts.trans, {'none', 'psc'}))
    opts.trans = 'none';
else
    opts.trans = lower(opts.trans(:)');
end

% try load SPMs and store essential information
spmc = cell2struct(cell(1, numel(spms), 9), ...
    {'filename', 'filepath', 'Vbeta', 'nSess', ...
     'xXsize', 'xXname', 'xXrgbf', 'xXsess', 'xXuname'}, 3);

for sc = 1:numel(spms)
    try
        if ~ischar(spms{sc}) || ...
            isempty(spms{sc})
            spms{sc} = sprintf('No/empty string at position %d.', sc);
            error('BADSTRING');
        end
        spms{sc} = spms{sc}(:)';
        s = load(spms{sc});
        if ~isfield(s, 'SPM')
            s = struct('SPM', s);
        end
        if ~isfield(s.SPM, 'Vbeta') || ...
           ~isfield(s.SPM, 'xX') || ...
           ~isstruct(s.SPM.xX)
            error('INVALID_SPM');
        end
        if ~isstruct(s.SPM.Vbeta)
            if iscell(s.SPM.Vbeta)
                for bc = 1:numel(s.SPM.Vbeta)
                    if ~isstruct(s.SPM.Vbeta{bc})
                        if ischar(s.SPM.Vbeta{bc})
                            s.SPM.Vbeta{bc} = ...
                                struct('fname', s.SPM.Vbeta{bc}(:)');
                        else
                            error('INVALID_SPM');
                        end
                    end
                end
                s.SPM.Vbeta = cat(1, s.SPM.Vbeta{:});
            else
                error('INVALID_SPM');
            end
        end
        if ~isfield(s.SPM.xX, 'name')
            if isfield(s.SPM.xX, 'Xnames')
                s.SPM.xX.name = s.SPM.xX.Xnames;
            else
                error('INVALID_SPM');
            end
        end
        spmc(sc).filename = spms{sc};
        spmc(sc).filepath = [fileparts(spms{sc}), filesep];
        spmc(sc).Vbeta = strrep({s.SPM.Vbeta(:).fname}, 'beta', ...
            [spmc(sc).filepath, filesep, 'beta']);
        spmc(sc).xXsize = size(s.SPM.xX.X, 1);
        spmc(sc).xXname = s.SPM.xX.name;
        if numel(spmc(sc).Vbeta) ~= numel(spmc(sc).xXname)
            error('INVALID_SPM');
        end
        spmc(sc).Vbeta = regexprep(spmc(sc).Vbeta, '\.img', '.hdr', 'preservecase');
        spmc(sc).xXrgbf = regexprep(spmc(sc).xXname, '^.*\*bf\((\d+)\)', '$1');
        spmc(sc).xXsess = regexprep(spmc(sc).xXname, '^.*Sn\((\d+)\).*$', '$1');
        spmc(sc).xXname = regexprep(regexprep(spmc(sc).xXname, ...
            '^.*Sn\(\d+\)\s*', ''), '\s*\*bf\(\d+\).*$', '');
        [spmc(sc).xXuname, foi, spmc(sc).xXuidx] = unique(spmc(sc).xXname);
        spmc(sc).nSess = str2double(spmc(sc).xXsess{end});
    catch
        error( ...
            'BVQXtools:SPMError', ...
            'Invalid SPM.mat file: %s.', ...
            spms{sc} ...
        );
    end
end

% subject ID's ?
if isempty(opts.subjids)
    subjids = char(spms);
    subjids = cellstr(subjids(:, findfirst(any(diff(subjids))):end));
    subjidl = 0;
    for sc = 1:numel(subjids)
        subjids{sc} = fileparts(subjids{sc});
        subjidl = max(subjidl, numel(subjids{sc}));
    end
    if numel(opts.subjids) > 1
        subjidl = reshape(sprintf(sprintf('%%%ds', subjidl), subjids{:}), ...
            subjidl, numel(subjids))';
        subjidl = subjidl(:, 1:findfirst(any(diff(subjidl)), -1));
        for sc = 1:numel(subjids)
            subjids{sc} = strrep(subjidl(sc, :), ' ', '');
        end
    end
    opts.subjids = subjids;
end

% time points
timepoints = {spmc(:).xXsize};
timepoints = cat(1, timepoints{:});
nroftotaltimepoints = sum(timepoints);

% check spatial layout/dimension
Vbetaobj = cell(1, numel(spmc));
for sc = 1:numel(spmc)
    try
        Vbetaobj{sc} = BVQXfile(spmc(sc).Vbeta{1});
    catch
        clearbvqxobjects(Vbetaobj);
        error( ...
            'BVQXtools:BadArgument', ...
            'Invalid Analyze/NIftI beta_0001 file for SPM.mat: %s', ...
            spmc(sc).filename ...
        );
    end
end
VResDims = zeros(numel(spmc), 19);
for sc = 1:numel(spmc)
    VResDims(sc, :) = [lsqueeze(Vbetaobj{sc}.CoordinateFrame.Trf(:))', ...
        Vbetaobj{sc}.CoordinateFrame.Dimensions(1:3)];
end
if any(any(diff(VResDims, 1, 1)))
    warning( ...
        'BVQXtools:SPMWarning', ...
        'Incompatible map sizes. Output must be taken carefully!!' ...
    );
end

% no conditions named
if isempty(opts.cond)
    
    % create list from first subject (in order of appearance)
    uname = spmc(1).xXuname;
    sname = uname;
    uidx = spmc(1).xXuidx;
    for cc = 1:numel(spmc(1).xXuname)
        sname{cc} = uname{uidx(1)};
        uidx(uidx == uidx(1)) = [];
    end
    
    % now check whether all conditions are available in all other subjects!
    for sc = 2:numel(spmc)
        for cc = numel(sname):-1:1
            if ~any(strcmpi(spmc(sc).xXuname, sname{cc}))
                sname(cc) = [];
            end
        end
    end
    
    % conditions left
    if isempty(sname)
        clearbvqxobjects(Vbetaobj);
        error( ...
            'BVQXtools:BadArgument', ...
            'Condition names don''t match between subject.' ...
        );
    end
    
    % put into cond list
    opts.cond(numel(sname)).bvname = '';
    for cc = 1:numel(sname)
        opts.cond(cc).bvname = sname{cc};
        opts.cond(cc).color = [floor(255.999 * rand(1, 3)); zeros(3, 3)];
        opts.cond(cc).spmname = sname{cc};
    end
    opts.cond(end).color = 255 .* [ones(1, 3); zeros(3, 3)];
    
% for named conditions
else
    
    % check they exist in all subjects
end

% get spm condition names
spmcn = {opts.cond(:).spmname};
consti = findfirst(~isemptycell(regexpi(spmcn, 'constant')));
if ~isempty(consti)
    if consti < numel(opts.cond)
        opts.cond = opts.cond(:);
        constcond = opts.cond(consti);
        opts.cond(consti) = [];
        opts.cond(end + 1) = constcond;
    end
else
    opts.cond(end + 1) = struct('bvname', 'constant', ...
        'color', 255 * [ones(1, 3); zeros(3, 3)], 'spmname', 'constant');
end

% make sure SPM names are patterns alright
for cc = 1:numel(opts.cond)
    if opts.cond(cc).spmname(1) ~= '^'
        opts.cond(cc).spmname = ['^' opts.cond(cc).spmname];
    end
    if opts.cond(cc).spmname(end) ~= '$'
        opts.cond(cc).spmname(end+1) = '$';
    end
end

% check resolution
if isempty(opts.res)
    opts.res = floor(mean(sqrt(sum( ...
        Vbetaobj{1}.CoordinateFrame.Trf(1:3, 1:3) .^ 2))));
end

% temporary clean-up
clearbvqxobjects(Vbetaobj);

% create GLM structure
glm = BVQXfile('new:glm');

% make some initial settings
glm.ProjectType = 1;
glm.ProjectTypeRFX = 1;
glm.NrOfSubjects = numel(spmc);
glm.NrOfSubjectPredictors = numel(opts.cond);
glm.NrOfTimePoints = nroftotaltimepoints;
glm.NrOfPredictors = numel(spmc) * glm.NrOfSubjectPredictors;
glm.NrOfConfounds = numel(spmc);
glm.NrOfStudies = numel(spmc);
glm.NrOfStudiesWithConfounds = numel(spmc);
glm.NrOfConfoundsPerStudy = ones(1, numel(spmc));
glm.SeparatePredictors = 2;
glm.Resolution = opts.res;
glm.SerialCorrelation = 0;
glm.Study(numel(spmc)).NrOfTimePoints = 0;
glm.Predictor(glm.NrOfPredictors).Name1 = '';
glm.GLMData = struct('RFXGlobalMap', single(0), ...
    'Subject', struct('BetaMaps', single(0)));
prc = 1;

% initialize progress bar
if isempty(opts.pbar)
    try
        pbar = BVQXprogress;
        BVQXprogress(pbar, 'setposition', [80, 200, 640, 36]);
        BVQXprogress(pbar, 'settitle', ...
            sprintf('Importing %d subjects'' SPM.mat to RFX-GLM...', numel(spmc)));
        BVQXprogress(pbar, 0, 'Importing subject ...', 'visible', 0, 1);
        pbarn = '';
    catch
        pbar = [];
    end
else
    pbar = opts.pbar;
    pbar.Progress(0, ...
        sprintf('importrfxglmfromspms: Importing subject 1/%d...', numel(spmc)));
    pbarn = 'importrfxglmfromspms: ';
end

% iterate over subjects
for sc = 1:numel(spmc)
    
    % update progress bar
    if ~isempty(pbar)
        pbar.Progress((sc - 1) / numel(spmc), ...
            sprintf('%sImporting subject ''%s'' (%d/%d)...', pbarn, ...
            opts.subjids{sc}, sc, numel(spmc)));
    end
    
    % temporarily import beta maps into VMP
    bvmp = importvmpfromspms(spmc(sc).Vbeta, 'b', ...
        opts.bbox, opts.res, opts.imeth);
    
    % GLM settings
    if sc == 1
        glm.XStart = bvmp.XStart;
        glm.XEnd = bvmp.XEnd;
        glm.YStart = bvmp.YStart;
        glm.YEnd = bvmp.YEnd;
        glm.ZStart = bvmp.ZStart;
        glm.ZEnd = bvmp.ZEnd;
        glm.GLMData.RFXGlobalMap = single(zeros(size(bvmp.Map(1).VMPData)));
        glm.GLMData.Subject(1).BetaMaps = ...
            single(zeros([size(bvmp.Map(1).VMPData), glm.NrOfSubjectPredictors]));
        glm.GLMData.Subject(2:numel(spmc)) = glm.GLMData.Subject(1);
        omask = zeros(size(bvmp.Map(1).VMPData));
    end
    
    % update progress bar for import
    if ~isempty(pbar)
        pbar.Progress((sc - 0.4) / numel(spmc), sprintf( ...
            '%sCombining runs and transforming data (%d/%d)...', ...
            pbarn, sc, numel(spmc)));
    end
    
    % set study & predictors
    glm.Study(sc).NrOfTimePoints = timepoints(sc);
    glm.Study(sc).NameOfAnalyzedFile = ...
        [spmc(sc).filepath, filesep, opts.subjids{sc}, '_SPM.vtc'];
    glm.Study(sc).NameOfRTCFile = '<SPM.xX.X>';
    for pc = 1:(numel(opts.cond) - 1)
        glm.Predictor(prc).Name1 = sprintf('Predictor: %d', prc);
        glm.Predictor(prc).Name2 = ...
            sprintf('Subject %s: %s', opts.subjids{sc}, opts.cond(pc).bvname);
        glm.Predictor(prc).RGB = opts.cond(pc).color;
        prc = prc + 1;
    end
    
    % put VMPData together
    vmpd = bvmp.Map;
    vmpd = {vmpd(:).VMPData};
    vmpd = cat(4, vmpd{:});
    bvmp.ClearObject;
    
    % update mask Inf/NaN
    mask = (~any(isinf(vmpd), 4) & ~any(isnan(vmpd), 4));
    vmpd(isinf(vmpd) | isnan(vmpd)) = 0;
    
    % update mask with mean-masking factor
    mnm = (1 ./ spmc(sc).nSess) .* sum(vmpd(:, :, :, end+1-spmc(sc).nSess:end), 4);
    mmm = minmaxmean(mnm);
    mnm = mnm < (opts.mmaskfac * mmm(3));
    vmpd(mnm(:, :, :, ones(1, size(vmpd, 4)))) = 0;
    
    % update mask general and across subjects
    mask = mask & (~all(vmpd == 0, 4));
    omask = omask + double(mask);
    
    % PSC-transform ?
    if strcmpi(opts.trans, 'psc')
        for pc = 1:size(vmpd, 4)
            vmpd(:, :, :, pc) = 100 .* (vmpd(:, :, :, pc) ./ ...
                vmpd(:, :, :, end - spmc(sc).nSess + str2double(spmc(sc).xXsess{pc})));
        end
        vmpd(isinf(vmpd) | isnan(vmpd)) = 0;
    end
    
    % combine beta maps (plain average for now)
    for pc = 1:numel(opts.cond)
        
        % find beta maps of condition
        uidx = find(~isemptycell(regexpi(spmc(sc).xXuname, opts.cond(pc).spmname)));
        bmci = [];
        for uic = 1:numel(uidx)
            bmca = find(spmc(sc).xXuidx == uidx(uic));
            bmci = [bmci, bmca(:)'];
        end
        
        % combine maps as average
        glm.GLMData.Subject(sc).BetaMaps(:, :, :, pc) = ...
            (1 / numel(bmci)) .* sum(vmpd(:, :, :, bmci), 4);
    end
end

% apply final masking
glm.GLMData.RFXGlobalMap = single(omask >= (0.75 * numel(spmc)));
glm.NrOfVoxelsForBonfCorrection = ...
    double(sum(glm.GLMData.RFXGlobalMap(:)));
omask = repmat(omask < (0.75 * numel(spmc)), [1, 1, 1, numel(opts.cond)]);
for sc = 1:numel(spmc)
    glm.GLMData.Subject(sc).BetaMaps(omask) = 0;
end

% add last predictors
for sc = 1:numel(spmc)
    glm.Predictor(prc).Name1 = sprintf('Predictor: %d', prc);
    glm.Predictor(prc).Name2 = ...
        sprintf('Subject %s: constant', opts.subjids{sc});
    glm.Predictor(prc).RGB = opts.cond(end).color;
    prc = prc + 1;
end

% close progress bar
if ~isempty(pbar) && ...
    isempty(opts.pbar)
    closebar(pbar);
end

% clean up
bless(glm, 1);

% save ?
if ~isempty(opts.filename)
    try
        glm.SaveAs(opts.filename(:)');
    catch
        warning( ...
            'BVQXtools:SaveError', ...
            'Error saving GLM file (%s). Please do so manually.', ...
            lasterr ...
        );
    end
end



% UI functions
function ig_closeui(varargin)
global BVQXui;
hFig = BVQXui.importrfxglmfromspms.hFig;
hFig.CloseRequestFcn = '';
hFig.Delete;

function ig_btbrowse(varargin)
global BVQXui;
hTag = BVQXui.importrfxglmfromspms.hTag;

% request one SPM.mat file
[spmfile, spmpath] = uigetfile( ...
    {'SPM.mat', 'SPM design matrices (SPM.mat)'}, ...
    'Please select one of the SPM.mat files to import...', ...
    'MultiSelect', 'off');
if isequal(spmfile, 0) || ...
    isequal(spmpath, 0)
    return;
end

% try loading
spmfile = [spmpath '/' spmfile];
try
    tSPM = load(spmfile);
    tSPM = tSPM.SPM;
    Sess = tSPM.Sess;
catch
    uiwait(warndlg('Invalid SPM.mat file selected.', ...
        'Import RFX-GLM from SPM: Warning', 'modal'));
    return;
end

% put the filename into the edit field
hTag.ED_importrfxglm_folder.String = spmfile;
hTag.ED_importrfxglm_folder.Enable = 'on';
hTag.BT_importrfxglm_search.Enable = 'on';

% look for conditions?
if hTag.CB_importrfxglm_autcond.Value > 0
    clist = {};
    for sc = 1:numel(Sess)
        for cc = 1:numel(Sess(sc).U)
            if ~any(strcmpi(Sess(sc).U(cc).name{1}, clist))
                clist{end+1} = Sess(sc).U(cc).name{1};
            end
        end
    end
    hTag.LB_importrfxglm_spmcond.String = clist;
    hTag.LB_importrfxglm_glmcond.String = clist;
end

function ig_btsearch(varargin)
global BVQXui;
hTag = BVQXui.importrfxglmfromspms.hTag;

% perform findfiles
pattf = fileparts(hTag.ED_importrfxglm_folder.String);
try
    spms = findfiles(pattf, 'SPM.mat', 'depth=1');
catch
    uiwait(warndlg('Invalid search pattern given.', ...
        'Import RFX-GLM from SPM: Warning', 'modal'));
    return;
end

% put into list of SPMs
hTag.LB_importrfxglm_files.String = spms;
if numel(spms) > 2
    hTag.BT_importrfxglm_import.Enable = 'on';
end

function ig_btfileup(varargin)
global BVQXui;
BVQXui.importrfxglmfromspms.hTag.LB_importrfxglm_files.MultiMove(-1);

function ig_btfiledown(varargin)
global BVQXui;
BVQXui.importrfxglmfromspms.hTag.LB_importrfxglm_files.MultiMove(1);

function ig_btfileadd(varargin)
global BVQXui;
hTag = BVQXui.importrfxglmfromspms.hTag;

% request one SPM.mat file
[spmfile, spmpath] = uigetfile( ...
    {'SPM.mat', 'SPM design matrices (SPM.mat)'}, ...
    'Please select an SPM.mat file to import...', ...
    'MultiSelect', 'off');
if isequal(spmfile, 0) || ...
    isequal(spmpath, 0)
    return;
end

% try loading
spmfile = [spmpath '/' spmfile];
try
    tSPM = load(spmfile);
    tSPM = tSPM.SPM;
    Sess = tSPM.Sess;
catch
    uiwait(warndlg('Invalid SPM.mat file selected.', ...
        'Import RFX-GLM from SPM: Warning', 'modal'));
    return;
end

% put the filename into the edit field
hTag.LB_importrfxglm_files.AddString(spmfile);
if hTag.LB_importrfxglm_files.MultiSize > 2
    hTag.BT_importrfxglm_import.Enable = 'on';
end

% look for conditions?
if hTag.CB_importrfxglm_autcond.Value > 0
    clist = hTag.LB_importrfxglm_spmcond.String;
    glist = hTag.LB_importrfxglm_glmcond.String;
    if ~iscell(clist)
        clist = cellstr(clist);
    end
    if ~iscell(glist)
        glist = cellstr(glist);
    end
    for sc = 1:numel(Sess)
        for cc = 1:numel(Sess(sc).U)
            if ~any(strcmpi(Sess(sc).U(cc).name{1}, clist))
                clist{end+1} = Sess(sc).U(cc).name{1};
                glist{end+1} = Sess(sc).U(cc).name{1};
            end
        end
    end
    hTag.LB_importrfxglm_spmcond.String = clist;
    hTag.LB_importrfxglm_glmcond.String = glist;
end

function ig_btfileremove(varargin)
global BVQXui;
hTag = BVQXui.importrfxglmfromspms.hTag;

% remove any selected values
sidx = hTag.LB_importrfxglm_files.Value;
if ~isempty(sidx)
    files = hTag.LB_importrfxglm_files.String;
    if ~iscell(files)
        files = cellstr(files);
    end
    files(sidx) = [];
    hTag.LB_importrfxglm_files.String = files;
    hTag.LB_importrfxglm_files.Value = [];
    if numel(files) < 3
        hTag.BT_importrfxglm_import.Enable = 'off';
    end
end

function ig_lbspmcselect(varargin)
global BVQXui;
hTag = BVQXui.importrfxglmfromspms.hTag;
try
    hTag.LB_importrfxglm_glmcond.Value = hTag.LB_importrfxglm_spmcond.Value;
catch
    % do nothing
end

function ig_lbglmcselect(varargin)
global BVQXui;
hTag = BVQXui.importrfxglmfromspms.hTag;
try
    hTag.LB_importrfxglm_spmcond.Value = hTag.LB_importrfxglm_glmcond.Value;
catch
    % do nothing
end

function ig_btcondup(varargin)
global BVQXui;
BVQXui.importrfxglmfromspms.hTag.LB_importrfxglm_spmcond.MultiMove(-1);
BVQXui.importrfxglmfromspms.hTag.LB_importrfxglm_glmcond.MultiMove(-1);

function ig_btconddown(varargin)
global BVQXui;
BVQXui.importrfxglmfromspms.hTag.LB_importrfxglm_spmcond.MultiMove(1);
BVQXui.importrfxglmfromspms.hTag.LB_importrfxglm_glmcond.MultiMove(1);

function ig_btcondadd(varargin)
global BVQXui;
hTag = BVQXui.importrfxglmfromspms.hTag;

% request two names
cnames = inputdlg({'Please enter the name as it occurs in the SPM.mat files:', ...
    'Please enter the name as it is to appear in the GLM file:'}, ...
    'Import GLM from SPM.mat files - Request', 1, {'spmcond', 'glmcond'}, ...
    struct('Resize', 'off', 'WindowStyle', 'modal'));

% test that the names are unique
spmc = hTag.LB_importrfxglm_spmcond.String;
if ~iscell(spmc)
    spmc = cellstr(spmc);
end
glmc = hTag.LB_importrfxglm_glmcond.String;
if ~iscell(glmc)
    glmc = cellstr(glmc);
end
if any(strcmpi(cnames{1}, spmc)) || ...
    any(strcmpi(cnames{2}, glmc))
    uiwait(warndlg('Condition names must be unique.', ...
        'Import RFX-GLM from SPM: Warning', 'modal'));
    return;
end
hTag.LB_importrfxglm_spmcond.AddString(cnames{1});
hTag.LB_importrfxglm_glmcond.AddString(cnames{2});

function ig_btcondremove(varargin)
global BVQXui;
hTag = BVQXui.importrfxglmfromspms.hTag;

% remove any selected values
sidx = hTag.LB_importrfxglm_spmcond.Value;
sid2 = hTag.LB_importrfxglm_glmcond.Value;
if ~isempty(sidx) && ...
    isequal(sidx, sid2)
    spmc = hTag.LB_importrfxglm_spmcond.String;
    if ~iscell(spmc)
        spmc = cellstr(spmc);
    end
    glmc = hTag.LB_importrfxglm_glmcond.String;
    if ~iscell(glmc)
        glmc = cellstr(glmc);
    end
    spmc(sidx) = [];
    glmc(sidx) = [];
    hTag.LB_importrfxglm_spmcond.String = spmc;
    hTag.LB_importrfxglm_glmcond.String = glmc;
    hTag.LB_importrfxglm_spmcond.Value = [];
    hTag.LB_importrfxglm_glmcond.Value = [];
end

function ig_toggleautocond(varargin)
global BVQXui;
st = BVQXui.importrfxglmfromspms;
if st.hTag.CB_importrfxglm_autcond.Value > 0
    st.hFig.SetGroupEnabled('MCond', 'off');
else
    st.hFig.SetGroupEnabled('MCond', 'on');
end

function ig_toggleautores(varargin)
global BVQXui;
st = BVQXui.importrfxglmfromspms;
if st.hTag.CB_importrfxglm_autores.Value > 0
    st.hFig.SetGroupEnabled('MResBox', 'off');
else
    st.hFig.SetGroupEnabled('MResBox', 'on');
end

function ig_btimport(varargin)
global BVQXui;
st = BVQXui.importrfxglmfromspms;
hTag = st.hTag;

% get settings
spms = hTag.LB_importrfxglm_files.String;
if ~iscell(spms)
    spms = cellstr(spms);
end
if numel(spms) < 3
    uiwait(warndlg('Too few SPM.mat files to import.', ...
        'Import RFX-GLM from SPM: Warning', 'modal'));
    return;
end
opts = struct;
spmc = hTag.LB_importrfxglm_spmcond.String;
glmc = hTag.LB_importrfxglm_glmcond.String;
if ~iscell(spmc)
    spmc = cellstr(spmc);
end
if ~iscell(glmc)
    glmc = cellstr(glmc);
end
if numel(spmc) ~= numel(glmc) || ...
    numel(unique(spmc)) ~= numel(spmc) || ...
    numel(unique(spmc)) ~= numel(spmc)
    uiwait(warndlg('Invalid condition name configuration.', ...
        'Import RFX-GLM from SPM: Warning', 'modal'));
    return;
end
if hTag.CB_importrfxglm_autores.Value > 0
    opts.bbox = [];
    opts.res = [];
else
    try
        opts.bbox = ...
            reshape(eval(['[' hTag.ED_importrfxglm_bbox.String ']']), ...
            2, 3);
    catch
        uiwait(warndlg('Invalid bounding box.', ...
            'Import RFX-GLM from SPM: Warning', 'modal'));
        return;
    end
    try
        opts.res = round(str2double(hTag.ED_importrfxglm_res.String));
    catch
        uiwait(warndlg('Invalid resolution value.', ...
            'Import RFX-GLM from SPM: Warning', 'modal'));
        return;
    end
end
opts.cond = cell2struct([glmc(:), spmc(:)], {'bvname', 'spmname'}, 2);
fname = hTag.ED_importrfxglm_target.String;
fname = fname(:)';
if ~any(fname == '<' & fname == '>') && ...
    numel(fname) > 4
    strcmpi(fname(end-3:end), '.glm')
    opts.filename = fname;
end
opts.pbar = st.pbar;
if hTag.CB_importrfxglm_psctr.Value > 0
    opts.trans = 'psc';
else
    opts.trans = 'none';
end
try
    st.hFig.Visible = 'off';
    BVQXui.importrfxglmfromspms.glm = importrfxglmfromspms(spms, opts);
catch
    uiwait(warndlg(sprintf('An error occurred during the import:\n\n%s', ...
        lasterr), 'Import RFX-GLM from SPM: Warning', 'modal'));
end
st.hFig.CloseRequestFcn = '';
st.hFig.Delete;
